package org.jcms.service.base;

import java.io.Serializable;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.jcms.model.PageBean;
import org.jcms.uitils.GenericsUtils;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * Dao层模版类
 * 
 * @author 赵泽洋
 * 
 * @param <T>
 *            要实现基本操作的bean的类
 * 
 */
@Transactional
@Repository
public class GenericDaoImpl<T extends Serializable> implements GenericDaoI<T> {

	/**
	 * 获取实体类类型
	 */
	@SuppressWarnings("unchecked")
	protected Class<T> persistentClass = GenericsUtils
			.getSuperClassGenricType(this.getClass());

	/**
	 * 若反射获得泛型类类型失效，则由此方法手动设置
	 * 
	 * @param entityClass
	 *            实体类类型
	 */
	public void setEntityClass(Class<T> entityClass) {
		this.persistentClass = entityClass;
	}

	/**
	 * 由spring管理的SessionFactory,注解获取
	 */
	@Resource
	protected SessionFactory sessionFactory;

	@Override
	public void create(T entity) {
		sessionFactory.getCurrentSession().persist(entity);
	}

	@Override
	public void createOrUpdate(T entity) {
		sessionFactory.getCurrentSession().saveOrUpdate(entity);
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	// 查询不需要开事务
	public T findById(Serializable id) {
		if (id == null)
			throw new RuntimeException(this.persistentClass.getName()
					+ ":传入的实体id不能为空");
		Object object = sessionFactory.getCurrentSession().get(
				this.persistentClass, id);
		return (T) object;
	}

	@Override
	public void deleteById(Serializable... entityids) {
		Session session = sessionFactory.getCurrentSession();
		for (Serializable id : entityids) {
			session.delete(session.get(this.persistentClass, id));
		}

	}

	@Override
	public void update(T entity) {
		sessionFactory.getCurrentSession().merge(entity);
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	// 查询不需要开事务
	public List<T> findAll() {
		return this.findByCriteria();
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	// 查询不需要开事务
	public List<T> findByHQL(String strHQL, Object... params) {

		Session session = sessionFactory.getCurrentSession();
		Query query = session.createQuery(strHQL);
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params[i]);
		}
		return query.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	// 查询不需要开事务
	public PageBean<T> findByPage(String strHQL, int currentPage, int pageSize,
			Object... params) {
		// 步骤1：创建一个PageBean对象
		PageBean<T> pageBean = new PageBean<T>();
		// 步骤2：获取一个数据库链接session
		Session session = sessionFactory.getCurrentSession();
		// 步骤3：执行HQL语句完成查询动获取本页内的固定条数的数据
		Query query = session.createQuery(strHQL);
		// 步骤4：设置查询条件-参数条件
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params[i]);
		}
		// 步骤5：设置查询条件-每页的启始记录下标 (当前也是-1)*每页个数
		query.setFirstResult((currentPage - 1) * pageSize);
		// 步骤6：设置查询条件-控制查询记录的个数
		query.setMaxResults(pageSize);
		// 步骤7：获取数据集合并且赋值给pageBean对象的data属性
		pageBean.setData(query.list());

		// 步骤8：将输入的HQL语句动态查分成符合返回记录个数的HQL语句
		strHQL = "select count(*) "
				+ strHQL.substring(strHQL.toLowerCase().indexOf("from"));
		// 步骤9：执行HQL语句完成查询动获取本页内的固定条数的数据
		query = session.createQuery(strHQL);
		// 步骤10：设置查询条件-参数条件
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params[i]);
		}
		// 步骤11：获取查询结果并且赋值给pageBean对象的totalRows
		pageBean.setTotalRows(Integer.parseInt(query.uniqueResult().toString()));
		// 步骤12：为剩余的pageBean属性赋值
		pageBean.setCurrentPage(currentPage);
		pageBean.setPageSize(pageSize);
		return pageBean;

	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	// 查询不需要开事务
	public List<T> findByCriteria(Criterion... prams) {
		Session session = sessionFactory.getCurrentSession();
		Criteria criteria = session.createCriteria(this.persistentClass);
		for (Criterion criterion : prams) {
			criteria.add(criterion);
		}
		return criteria.list();
	}

	@Override
	public long count() {
		
		Criteria c = sessionFactory.getCurrentSession().createCriteria(
				this.persistentClass);

		c.setProjection(Projections.rowCount());

		return Long.parseLong(c.uniqueResult().toString());
	}

}
